package com.wdz.websocket;

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wdz.redis.RedisUtil;
import com.wdz.service.UserService;
import com.wdz.utils.TokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * @ServerEndpoint 注解是一个类层次的注解，它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 * @Component 可以把当前类变成websocket服务类
 */
@ServerEndpoint("/way/{param}")
@Component
public class WebSocket {
	//静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户id
    public static ConcurrentHashMap<String, WebSocket> webSocketSet = new ConcurrentHashMap<String, WebSocket>();

  //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

  //当前发消息的人员编号
    private String userId = "";


    /**
     * 线程安全的统计在线人数
     *
     * @return
     */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        onlineCount--;
    }

    private static TokenUtils tokenUtils;

    private static RedisUtil redisUtil;

    private static UserService userService;
    @Autowired
    public void setTokenUtils(TokenUtils tokenUtils) {
        WebSocket.tokenUtils = tokenUtils;
    }
    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        WebSocket.redisUtil = redisUtil;
    }
    @Autowired
    public void setUserService(UserService userService) {
        WebSocket.userService = userService;
    }

    /**
     * 连接建立成功调用的方法
     *@PathParam 使用url占位符的方式绑定参数
     * @param param   用户唯一标识
     * @param session 可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(@PathParam(value = "param") String param, Session session) {
       //userId = param;//接收到发送消息的人员编号
        //System.out.println(userId);
        JSONObject jsonObject = JSON.parseObject("{"+param+"}");
        //userId = tokenUtils.getUsernameFromToken(jsonObject.getString("user"));
        userId = jsonObject.getString("user");
        String ip = jsonObject.getString("ip");
        this.session = session;
        webSocketSet.put(userId, this);//加入线程安全map中
        addOnlineCount();           //在线数加1
        if(!userService.checkIsLogin(tokenUtils.getUsernameFromToken(userId),ip)){
            new RuntimeException("该用户已被登录");
        }
        System.out.println("连接成功 " + userId  +" 人数 "+ getOnlineCount());
    }
    
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (!userId.equals("")) {
            //根据id从redis中删除
            userService.deleteUserToRedis(tokenUtils.getUsernameFromToken(userId));
            webSocketSet.remove(userId);  //根据用户id从ma中删除
            subOnlineCount();           //在线数减1
            System.out.println("连接关闭" + userId  +" "+ getOnlineCount());
        }
    }
    
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("发送消息: " + message);
        JSONObject m = JSONObject.parseObject(message);
        //m.type == 0为发送心跳检测
        if(m.getIntValue("type") == 0){
            System.out.println("心跳检测，接受到sessionId为"+session.getId()+"的心跳");
        }else {
            //要发送人的用户uuid
            String sendUserId = m.getString("userId");
            //发送的信息
            String sendMessage = m.getString("message");

            //给指定的人发消息
            sendToUser(sendUserId, sendMessage);

            //给所有人发消息
            //sendAll(message);
        }
    }
    
    /**
     * 给指定的人发送消息
     *
     * @param message
     */
    public void sendToUser(String sendUserId, String message) {

        try {
            if (webSocketSet.get(sendUserId) != null) {
                webSocketSet.get(sendUserId).sendMessage(message);
                ///chatRecord.setStatus(2);
            } else {

				/*
				 * if (webSocketSet.get(userId) != null) {
				 * webSocketSet.get(userId).sendMessage(sendUserId); }
				 * System.out.println("消息接受人:" + sendUserId + "已经离线！");
				 */
            	//当对方不在线
            	//chatRecord.setStatus(1);
            }
        } catch (IOException e) {
            e.printStackTrace();
            //当发送失败
           // chatRecord.setStatus(0);
        } finally {
        	//将数据保存到数据库里面
        	//chatRecordService.sendMessage(chatRecord);
		}
    }
    /**
     * 管理员发送消息
     *
     * @param message
     */
    public void systemSendToUser(String sendUserId, String message) {

        try {
            if (webSocketSet.get(sendUserId) != null) {
                webSocketSet.get(sendUserId).sendMessage(message);
            } else {
                System.out.println("消息接受人:" + sendUserId + "已经离线！");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 给所有人发消息
     *
     * @param message
     */
    public void sendAll(String message) throws IOException {
        //String sendMessage = message.split(",")[0];
        //遍历HashMap
        for (String key : webSocketSet.keySet()) {
                //判断接收用户是否是当前发消息的用户
                if (!userId.equals(key)) {
                    webSocketSet.get(key).sendMessage(message);
                    System.out.println("key = " + key);
                }
        }
    }


    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("连接异常");
        error.printStackTrace();
    }

    /**
     * 发送消息
     *
     * @param message
     * @throws IOException
     */
    public void sendMessage(String message) throws IOException {
    	//同步发送
        this.session.getBasicRemote().sendText(message);
      //异步发送
        //this.session.getAsyncRemote().sendText(message);
    }
}
